home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / nasm095s.zip / OUTBIN.C < prev    next >
C/C++ Source or Header  |  1997-07-27  |  8KB  |  309 lines

  1. /* outbin.c    output routines for the Netwide Assembler to produce
  2.  *        flat-form binary files
  3.  *
  4.  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  5.  * Julian Hall. All rights reserved. The software is
  6.  * redistributable under the licence given in the file "Licence"
  7.  * distributed in the NASM archive.
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include "nasm.h"
  14. #include "nasmlib.h"
  15. #include "outform.h"
  16.  
  17. #ifdef OF_BIN
  18.  
  19. static FILE *fp;
  20. static efunc error;
  21.  
  22. static struct Section {
  23.     struct SAA *contents;
  24.     long length;
  25.     long index;
  26. } textsect, datasect;
  27. static long bsslen, bssindex;
  28.  
  29. static struct Reloc {
  30.     struct Reloc *next;
  31.     long posn;
  32.     long bytes;
  33.     long secref;
  34.     long secrel;
  35.     struct Section *target;
  36. } *relocs, **reloctail;
  37.  
  38. static long start_point;
  39.  
  40. static void add_reloc (struct Section *s, long bytes, long secref,
  41.                long secrel) {
  42.     struct Reloc *r;
  43.  
  44.     r = *reloctail = nasm_malloc(sizeof(struct Reloc));
  45.     reloctail = &r->next;
  46.     r->next = NULL;
  47.     r->posn = s->length;
  48.     r->bytes = bytes;
  49.     r->secref = secref;
  50.     r->secrel = secrel;
  51.     r->target = s;
  52. }
  53.  
  54. static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef) {
  55.     fp = afp;
  56.  
  57.     error = errfunc;
  58.     (void) ldef;               /* placate optimisers */
  59.  
  60.     start_point = 0L;               /* default */
  61.     textsect.contents = saa_init(1L);
  62.     datasect.contents = saa_init(1L);
  63.     textsect.length = datasect.length = 0;
  64.     textsect.index = seg_alloc();
  65.     datasect.index = seg_alloc();
  66.     bsslen = 0;
  67.     bssindex = seg_alloc();
  68.     relocs = NULL;
  69.     reloctail = &relocs;
  70. }
  71.  
  72. static void bin_cleanup (void) {
  73.     struct Reloc *r;
  74.     long datapos, dataalign, bsspos;
  75.  
  76.     datapos = (start_point + textsect.length + 3) & ~3;/* align on 4 bytes */
  77.     dataalign = datapos - (start_point + textsect.length);
  78.  
  79.     saa_rewind (textsect.contents);
  80.     saa_rewind (datasect.contents);
  81.  
  82.     bsspos = (datapos + datasect.length + 3) & ~3;
  83.  
  84.     for (r = relocs; r; r = r->next) {
  85.     unsigned char *p, *q, mydata[4];
  86.     long l;
  87.  
  88.     saa_fread (r->target->contents, r->posn, mydata, r->bytes);
  89.     p = q = mydata;
  90.     l = *p++;
  91.     l += ((long)*p++) << 8;
  92.     if (r->bytes == 4) {
  93.         l += ((long)*p++) << 16;
  94.         l += ((long)*p++) << 24;
  95.     }
  96.  
  97.     if (r->secref == textsect.index)
  98.         l += start_point;
  99.     else if (r->secref == datasect.index)
  100.         l += datapos;
  101.     else if (r->secref == bssindex)
  102.         l += bsspos;
  103.  
  104.     if (r->secrel == textsect.index)
  105.         l -= start_point;
  106.     else if (r->secrel == datasect.index)
  107.         l -= datapos;
  108.     else if (r->secrel == bssindex)
  109.         l -= bsspos;
  110.  
  111.     if (r->bytes == 4)
  112.         WRITELONG(q, l);
  113.     else
  114.         WRITESHORT(q, l);
  115.     saa_fwrite (r->target->contents, r->posn, mydata, r->bytes);
  116.     }
  117.     saa_fpwrite (textsect.contents, fp);
  118.     if (datasect.length > 0) {
  119.     fwrite ("\0\0\0\0", dataalign, 1, fp);
  120.     saa_fpwrite (datasect.contents, fp);
  121.     }
  122.     fclose (fp);
  123.     saa_free (textsect.contents);
  124.     saa_free (datasect.contents);
  125.     while (relocs) {
  126.     r = relocs->next;
  127.     nasm_free (relocs);
  128.     relocs = r;
  129.     }
  130. }
  131.  
  132. static void bin_out (long segto, void *data, unsigned long type,
  133.              long segment, long wrt) {
  134.     unsigned char *p, mydata[4];
  135.     struct Section *s;
  136.     long realbytes;
  137.  
  138.     if (wrt != NO_SEG) {
  139.     wrt = NO_SEG;               /* continue to do _something_ */
  140.     error (ERR_NONFATAL, "WRT not supported by binary output format");
  141.     }
  142.  
  143.     /*
  144.      * handle absolute-assembly (structure definitions)
  145.      */
  146.     if (segto == NO_SEG) {
  147.     if ((type & OUT_TYPMASK) != OUT_RESERVE)
  148.         error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
  149.            " space");
  150.     return;
  151.     }
  152.  
  153.     if (segto == bssindex) {           /* BSS */
  154.     if ((type & OUT_TYPMASK) != OUT_RESERVE)
  155.         error(ERR_WARNING, "attempt to initialise memory in the"
  156.           " BSS section: ignored");
  157.     s = NULL;
  158.     } else if (segto == textsect.index) {
  159.     s = &textsect;
  160.     } else if (segto == datasect.index) {
  161.     s = &datasect;
  162.     } else {
  163.     error(ERR_WARNING, "attempt to assemble code in"
  164.           " segment %d: defaulting to `.text'", segto);
  165.     s = &textsect;
  166.     }
  167.  
  168.     if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
  169.     if (segment != NO_SEG &&
  170.         segment != textsect.index &&
  171.         segment != datasect.index &&
  172.         segment != bssindex) {
  173.         if (segment % 2)
  174.         error(ERR_NONFATAL, "binary output format does not support"
  175.               " segment base references");
  176.         else
  177.         error(ERR_NONFATAL, "binary output format does not support"
  178.               " external references");
  179.         segment = NO_SEG;
  180.     }
  181.     if (s) {
  182.         if (segment != NO_SEG)
  183.         add_reloc (s, type & OUT_SIZMASK, segment, -1L);
  184.         p = mydata;
  185.         if ((type & OUT_SIZMASK) == 4)
  186.         WRITELONG (p, *(long *)data);
  187.         else
  188.         WRITESHORT (p, *(long *)data);
  189.         saa_wbytes (s->contents, mydata, type & OUT_SIZMASK);
  190.         s->length += type & OUT_SIZMASK;
  191.     } else
  192.         bsslen += type & OUT_SIZMASK;
  193.     } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
  194.     type &= OUT_SIZMASK;
  195.     p = data;
  196.     if (s) {
  197.         saa_wbytes (s->contents, data, type);
  198.         s->length += type;
  199.     } else
  200.         bsslen += type;
  201.     } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
  202.     if (s) {
  203.         error(ERR_WARNING, "uninitialised space declared in"
  204.           " %s section: zeroing",
  205.           (segto == textsect.index ? "code" : "data"));
  206.     }
  207.     type &= OUT_SIZMASK;
  208.     if (s) {
  209.         saa_wbytes (s->contents, NULL, type);
  210.         s->length += type;
  211.     } else
  212.         bsslen += type;
  213.     } else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
  214.            (type & OUT_TYPMASK) == OUT_REL4ADR) {
  215.     realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2);
  216.     if (segment != NO_SEG &&
  217.         segment != textsect.index &&
  218.         segment != datasect.index &&
  219.         segment != bssindex) {
  220.         if (segment % 2)
  221.         error(ERR_NONFATAL, "binary output format does not support"
  222.               " segment base references");
  223.         else
  224.         error(ERR_NONFATAL, "binary output format does not support"
  225.               " external references");
  226.         segment = NO_SEG;
  227.     }
  228.     if (s) {
  229.         add_reloc (s, realbytes, segment, segto);
  230.         p = mydata;
  231.         if (realbytes == 4)
  232.         WRITELONG (p, *(long*)data - realbytes - s->length);
  233.         else
  234.         WRITESHORT (p, *(long*)data - realbytes - s->length);
  235.         saa_wbytes (s->contents, mydata, realbytes);
  236.         s->length += realbytes;
  237.     } else
  238.         bsslen += realbytes;
  239.     }
  240. }
  241.  
  242. static void bin_deflabel (char *name, long segment, long offset,
  243.               int is_global) {
  244.     if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
  245.     error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
  246.     return;
  247.     }
  248.  
  249.     if (is_global == 2) {
  250.     error (ERR_NONFATAL, "binary output format does not support common"
  251.            " variables");
  252.     }
  253. }
  254.  
  255. static long bin_secname (char *name, int pass, int *bits) {
  256.     /*
  257.      * Default is 16 bits.
  258.      */
  259.     if (!name)
  260.     *bits = 16;
  261.  
  262.     if (!name)
  263.     return textsect.index;
  264.  
  265.     if (!strcmp(name, ".text"))
  266.     return textsect.index;
  267.     else if (!strcmp(name, ".data"))
  268.     return datasect.index;
  269.     else if (!strcmp(name, ".bss"))
  270.     return bssindex;
  271.     else
  272.     return NO_SEG;
  273. }
  274.  
  275. static long bin_segbase (long segment) {
  276.     return segment;
  277. }
  278.  
  279. static int bin_directive (char *directive, char *value, int pass) {
  280.     int rn_error;
  281.  
  282.     if (!strcmp(directive, "org")) {
  283.     start_point = readnum (value, &rn_error);
  284.     if (rn_error)
  285.         error (ERR_NONFATAL, "argument to ORG should be numeric");
  286.     return 1;
  287.     } else
  288.     return 0;
  289. }
  290.  
  291. static void bin_filename (char *inname, char *outname, efunc error) {
  292.     standard_extension (inname, outname, "", error);
  293. }
  294.  
  295. struct ofmt of_bin = {
  296.     "flat-form binary files (e.g. DOS .COM, .SYS)",
  297.     "bin",
  298.     bin_init,
  299.     bin_out,
  300.     bin_deflabel,
  301.     bin_secname,
  302.     bin_segbase,
  303.     bin_directive,
  304.     bin_filename,
  305.     bin_cleanup
  306. };
  307.  
  308. #endif /* OF_BIN */
  309.